(library (segment)
  (export make-segment
          segment-start
          segment-end
          segment-map
          segment)

  (import (except (rnrs base)
                  let-values
                  map)
          (only (guile)
                lambda* λ))

  (define make-segment
    (λ (start end)
      (cons start end)))

  (define segment-start
    (λ (seg)
      (car seg)))

  (define segment-end
    (λ (seg)
      (cdr seg)))

  (define segment-map
    (lambda* (proc seg #:key (next (λ (num) (+ num 1))))
      (let ([min-val (segment-start seg)]
            [max-val (segment-end seg)])
        (let iter ([current-val° min-val])
          (cond
           [(<= current-val° max-val)
            (cons (proc current-val°)
                  (iter (next current-val°)))]
           [else '()])))))

  (define segment
    (lambda* (start end segment-count #:key (next (λ (num) (+ num 1))))
      "Make segments of mostly equal length/size. A
segment's starting point is based on the previous segment's
ending point. Segments do not necessarily connect with no
gap in between. The NEXT argument is a function, which is
used to calculate the start of the starting point of the
following segment from the ending point of the previous
segment."
      (let ([segment-size
             (ceiling
              (/ (- end start)
                 segment-count))])
        (let loop ([pos start])
          (cond
           [(>= (+ pos segment-size) end)
            (list (make-segment pos end))]
           [else
            (cons (make-segment pos (+ pos segment-size))
                  (loop (next (+ pos segment-size))))]))))))
